#include <myFs/blockbuf.h>
#include <spdlog/spdlog.h>

namespace myFs {
namespace basic {
using namespace spdlog;
using size_t = std::uint32_t;

Buf::Buf(Inode& inode, Bitmap* pBlockbitmap)
    : m_inode(inode), m_pBitmap(pBlockbitmap) {}

size_t Buf::size() const { return m_inode.size; }

size_t Buf::read(char* dst, size_t nbytes, size_t off) {
    size_t cnt = 0;
    for (size_t i = off; i < off + nbytes && i < size(); ++i, ++dst) {
        *dst = at(i);
        ++cnt;
    }
    clock_gettime(CLOCK_REALTIME, &(m_inode.atim));
    return cnt;
}

size_t Buf::write(char const* src, size_t nbytes, size_t off) {
    if (size() < off + nbytes) {
        // alloc space
        int curnblk = size() / sizeof(Block);
        if (size() % sizeof(Block)) ++curnblk;
        int neednblk = (off + nbytes) / sizeof(Block);
        if ((off + nbytes) % sizeof(Block)) ++neednblk;
        while (curnblk < neednblk) {
            m_inode.addr[curnblk] = allocBlock();
            ++curnblk;
        }
        m_inode.size = off + nbytes;
    }
    for (size_t i = off; i < off + nbytes; ++i, ++src) {
        at(i) = *src;
    }
    clock_gettime(CLOCK_REALTIME, &(m_inode.mtim));
    return nbytes;
}

char& Buf::at(size_t i) {
    size_t index = i / sizeof(Block);
    size_t off = i % sizeof(Block);
    char* pblk = convertToAddr(m_inode.addr[index]);
    return *(pblk + off);
}

size_t Buf::allocBlock() { return m_pBitmap->alloc(1); }

char* Buf::convertToAddr(size_t bnum) const {
    return (char*)(m_pBitmap->convertToAddr(bnum));
}

}  // namespace basic

}  // namespace myFs